---
title: TCP/IP三次握手和四次挥手
date: '2023-04-01 12:12:12'
tags: ['面试', 'http']
draft: false
summary: 三次握手和四次挥手
---

### 三次握手

三次握手（Three-way Handshake）是指建立一个 TCP 连接时，需要客户端和服务器总共发送 3 个报文

刚开始客户端和服务器端都处于 CLOSED(关闭)状态，随后服务器进程处于 LISTEN(收听)状态，等待客户端的连接请求。

第一次握手（发送 SYN）：客户端向服务器发出连接请求，附带客户端序列号 seq，然后进入 SYN_SENT(同步已发送) 状态，等待服务器的确认。
第二次握手（发送 SYN+ACK）：服务器收到连接请求，同意建立连接，然后向客户段发送确认连接信息，附带向客户端连接请求，此时服务器进入 SYN_RCVD(同步收到) 状态。
第三次握手（发送 ACK）：客户端收到服务器的确认连接信息，向服务器发送确认连接，此时 TCP 连接已经建立，客户端进入 ESTABLISHED 状态。当服务器收到客户端发送的确认报文后也会进入 ESTABLISHED 状态，完成三次握手。

为什么需要三次握手，而不是二次握手？
三次握手的目的是为了防止已失效的连接请求突然又传送到了服务端，而产生错误。
假设采用两次握手建立连接，客户端第一次向服务端发送建立连接请求，因为网络延迟的原因，一直没有到达服务器。于是客户端再次向服务端重新发送建立连接请求，这次服务端收到连接请求后，向客户端回复确认，建立连接。但是这时网络延迟恢复，服务端又收到客户端第一次发送的连接请求，服务端认为客户端又发起了一次连接，再次回复确认，又建立了一个连接。
服务端认为有两个连接，客户端认为有一个连接，造成数据状态不一致。
至于为什么不像断开连接一样采用四次握手，因为服务端把确认连接请求和向客户端发送的建立连接请求合并成一次请求，发送给客户端了。

### 四次挥手

四次挥手是指断开一个 TCP 连接时，需要客户端和服务端总共发送 4 个报文以确认连接的断开。

第一次挥手（发送 FIN）：当通信的一方完成数据发送任务，需要关闭连接时，它会发送一个 FIN（结束）报文段，进入 FIN_WAIT_1 状态。无论是客户端还是服务端，任何一方都可以主动发起关闭连接的请求。
第二次挥手（发送 ACK）：服务端收到 FIN 报文段后，发送一个 ACK 报文段作为回应，并进入 CLOSE-WAIT 状态。客户端收到 ACK 后，进入 FIN-WAIT-2 状态。这时候已经断开了客户端与服务端的连接，服务端依然可以继续向客户端发送数据。
第三次挥手（发送 FIN）：服务器端完成数据传输后，发送一个 FIN 报文段，请求关闭连接，进入 LAST-ACK 状态。
第四次挥手（发送 ACK）：客户端收到服务器的 FIN 包后，发送 ACK 报文段作为回应，并进入 TIME-WAIT 状态。经过 2MSL 后，客户端才进入 CLOSED 状态。服务器端收到客户端的确认包 ACK 后进入 CLOSED 状态，连接被最终关闭。

为什么需要四次挥手？
由于 TCP 连接是全双工的，即数据可以在两个方向上流动，因此每个方向都必须要单独进行关闭，关闭一个方向上的连接需要一次请求和一次确认，最终需要四次请求。
为什么不能是三次，不能像建立连接那样把第二次和第三次合并成一次？
因为在第二次请求时服务端向客户端发送确认关闭连接，此时服务端可能还有一些数据没有传输完成，需要继续向客户端发送数据，不能跟合并服务器向客户端发送的关闭连接请求，所以需要拆分成两个连接请求。
